import argparse
import json
import os
import random
import time

import httpx

# 请求头
headers = {
    "accept": "application/json, text/plain, */*",
    "accept-encoding": "gzip, deflate, br, zstd",
    "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
    "origin": "https://www.bilibili.com",
    "priority": "u=1, i",
    "referer": "https://www.bilibili.com/",
    "sec-ch-ua": '"Chromium";v="140", "Not=A?Brand";v="24", "Microsoft Edge";v="140"',
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": '"Windows"',
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-site",
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0",
}

# API地址
API_URL = "https://api.bilibili.com/x/web-interface/view?bvid={bvid}"


def read_bvids_tags(tid: str, start: int, end: int) -> list:
    """从指定tid的文件中读取指定范围的BV号和标签"""
    file_path = os.path.join(".", "set", f"{tid}_bvids_tags_set.txt")

    try:
        with open(file_path, "r", encoding="utf-8") as f:
            lines = [line.strip() for line in f if line.strip()]

        start_idx = max(0, start - 1)
        end_idx = min(len(lines), end)

        bvids_tags = []
        for line in lines[start_idx:end_idx]:
            parts = line.split("\t\t")
            if len(parts) == 2:
                bvid, tags = parts
                bvids_tags.append((bvid, tags))
            else:
                print(f"格式错误，跳过行: {line}")

        print(f"成功读取 {len(bvids_tags)} 个BV号（从第{start}行到第{end}行）")
        return bvids_tags
    except FileNotFoundError:
        print(f"错误：找不到文件 {file_path}")
        return []
    except Exception as e:
        print(f"读取BV号文件失败: {e}")
        return []


def fetch_video_info(bvid: str, client: httpx.Client) -> dict | None:
    """获取单个视频的信息，带重试机制"""
    max_retries = 3
    retry_delay = 2

    for attempt in range(max_retries):
        try:
            url = API_URL.format(bvid=bvid)
            response = client.get(url, headers=headers)
            response.raise_for_status()

            data = response.json()

            if data.get("code") != 0:
                print(f"获取 {bvid} 失败: {data.get('message', '未知错误')}")
                return None

            video_data = data.get("data", {})
            stat_data = video_data.get("stat", {})
            owner_data = video_data.get("owner", {})

            # 这里只获取视频数据结构，不处理标签，标签将从文件中获取
            return {
                "bvid": video_data.get("bvid", ""),
                "tid": video_data.get("tid", 0),
                "title": video_data.get("title", ""),
                "duration": video_data.get("duration", 0),
                "pic": video_data.get("pic", ""),
                "pubdate": video_data.get("pubdate", 0),
                "mid": owner_data.get("mid", 0),
                "view": stat_data.get("view", 0),
                "danmaku": stat_data.get("danmaku", 0),
                "reply": stat_data.get("reply", 0),
                "like": stat_data.get("like", 0),
                "coin": stat_data.get("coin", 0),
                "favorite": stat_data.get("favorite", 0),
                "share": stat_data.get("share", 0),
            }

        except httpx.HTTPError as e:
            if attempt < max_retries - 1:
                print(
                    f"HTTP错误 (BV号: {bvid}), 正在重试 ({attempt + 1}/{max_retries}): {e}"
                )
                time.sleep(retry_delay)
                retry_delay *= 2
            else:
                print(f"HTTP错误 (BV号: {bvid})，已达最大重试次数: {e}")
        except Exception as e:
            print(f"获取视频信息失败 (BV号: {bvid}): {e}")
            break

    return None


def save_temp_data(data, temp_file):
    """临时保存数据到JSON文件，防止丢失"""
    try:
        with open(temp_file, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
    except Exception as e:
        print(f"临时保存数据失败: {e}")


def save_failed_bvids(failed_bvids, file_path):
    """保存失败的BV号到文件"""
    try:
        with open(file_path, "a", encoding="utf-8") as f:
            for bvid in failed_bvids:
                f.write(f"{bvid}\n")
        print(f"已保存 {len(failed_bvids)} 个失败的BV号到 {file_path}")
    except Exception as e:
        print(f"保存失败的BV号时出错: {e}")


def main():
    # 创建命令行参数解析器
    parser = argparse.ArgumentParser(description="B站视频数据获取工具")
    parser.add_argument("--tid", required=True, help="视频分类ID（如24）")
    parser.add_argument("--start", type=int, required=True, help="起始行号")
    parser.add_argument("--end", type=int, required=True, help="结束行号")

    # 解析参数
    args = parser.parse_args()

    # 验证参数
    if args.start < 1 or args.end < args.start:
        print("错误: start和end必须为正整数，且end >= start")
        return

    result_dir = os.path.join(".", "result")
    os.makedirs(result_dir, exist_ok=True)

    result_file = os.path.join(result_dir, f"{args.tid}_result.jsonl")
    temp_file = os.path.join(result_dir, f"{args.tid}_temp.json")
    failed_file = os.path.join(result_dir, f"{args.tid}_failed.txt")

    bvids_tags = read_bvids_tags(args.tid, args.start, args.end)
    if not bvids_tags:
        print("没有获取到BV号，程序退出")
        return

    with httpx.Client(timeout=10) as client:
        results = []
        failed_bvids = []
        total = len(bvids_tags)
        # 调整请求间隔为0.5-1.5秒
        min_delay = 0.10
        max_delay = 0.30

        for i, (bvid, tags) in enumerate(bvids_tags, 1):
            print(f"正在处理 {i}/{total}: {bvid}")

            video_info = fetch_video_info(bvid, client)
            if video_info:
                # 将从文件中获取的标签直接存入tag字段
                video_info["tag"] = tags
                results.append(video_info)

                if i % 10 == 0:
                    save_temp_data(results, temp_file)
                    print(f"已临时保存 {i} 条数据到 {temp_file}")
            else:
                failed_bvids.append(bvid)

            if i < total:
                delay = random.uniform(min_delay, max_delay)
                time.sleep(delay)

        save_temp_data(results, temp_file)

        if results:
            with open(result_file, "a", encoding="utf-8") as f:
                for item in results:
                    json.dump(item, f, ensure_ascii=False)
                    f.write("\n")
            print(f"成功追加 {len(results)}/{total} 条视频数据到 {result_file}")
        else:
            print("没有获取到任何视频数据，不追加到结果文件")

        if failed_bvids:
            save_failed_bvids(failed_bvids, failed_file)


if __name__ == "__main__":
    main()
